import base64
import pickle

from django.shortcuts import render

# Create your views here.
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response

from carts import constants
from goods.models import SKU
from .serializers import CartSerializer, CartSKUSerializer, CartDeleteSerializer, CartSelectAllSerializer


class CartView(GenericAPIView):
    """购物车"""
    serializer_class = CartSerializer

    def perform_authentication(self, request):
        """重写父类的用户验证方法，不在进入视图前就检查JWT,在post中判断用户登录状态"""
        pass

    def post(self, request):
        s = self.get_serializer(data=request.data)
        # 校验
        s.is_valid(raise_exception=True)

        # 提取可能会操作的数据
        sku_id = s.validated_data.get("sku_id")
        count = s.validated_data.get("count")
        selected = s.validated_data.get("selected")

        # 保存
        try:
            user = request.user
        except Exception as e:
            user = None
        # 登录用户保存在redis.没有user.is_authenticated  可能是匿名用户AnonymoseUser
        if user is not None and user.is_authenticated:
            redis_conn = get_redis_connection("cart")
            pl = redis_conn.pipeline()
            pl.hincrby('cart_%s' % user.id, sku_id, count)
            if selected:
                pl.sadd("cart_selected_%s" % user.id, sku_id)

            pl.execute()
            return Response(s.data)

        else:
            # 未登录用户保存在cookies中
            # 取出cookie中的购物车数据
            cookie_cart = request.COOKIES.get("cart")
            if cookie_cart:
                # 解析
                cart_str_bytes = cookie_cart.encode()  # 转换bytes
                cart_bytes = base64.b64decode(cart_str_bytes)
                cart_dict = pickle.loads(cart_bytes)
                # cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                # 没有数据,则为空
                cart_dict = {}
            if sku_id in cart_dict:
                # 商品在购物车中,累加
                cart_dict[sku_id]["count"] += count
                cart_dict[sku_id]["selected"] = selected
            else:
                # 商品不在购物车中,设置
                cart_dict[sku_id] = {
                    "count": count,
                    "selected": selected
                }
            cart_cookie = base64.b16encode(pickle.dumps(cart_dict)).decode()
            # 设置cookie
            response = Response(s.data)
            response.set_cookie("cart", cart_cookie, max_age=constants.CART_COOKIE_EXPIRES)
            return response

    def get(self, request):
        """查询购物车"""
        # 判断用户登录状态
        try:
            user = request.user
        except Exception:
            user = None

        # 查询
        if user and user.is_authenticated:
            # 如果用户已登录，从redis中查询  sku_id  count selected
            redis_conn = get_redis_connection('cart')
            redis_cart = redis_conn.hgetall('cart_%s' % user.id)
            # redis_cart = {
            #     商品的sku_id  bytes字节类型: 数量  bytes字节类型
            #     商品的sku_id  bytes字节类型: 数量  bytes字节类型
            #    ...
            # }
            redis_cart_selected = redis_conn.smembers(
                'cart_selected_%s' % user.id)
            # redis_cart_selected = set(勾选的商品sku_id bytes字节类型, ....)

            # 遍历 redis_cart，形成cart_dict
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in redis_cart_selected
                }
        else:
            # 如果用户未登录，从cookie中查询
            cookie_cart = request.COOKIES.get('cart')

            if cookie_cart:
                # 表示cookie中有购物车数据
                # 解析
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                # 表示cookie中没有购物车数据
                cart_dict = {}

        # cart_dict = {
        #     sku_id_1: {
        #         'count': 10
        #         'selected': True
        #     },
        #     sku_id_2: {
        #         'count': 10
        #         'selected': False
        #     },
        # }

        # 查询数据库
        sku_id_list = cart_dict.keys()
        sku_obj_list = SKU.objects.filter(id__in=sku_id_list)

        # 遍历sku_obj_list 向sku对象中添加count和selected属性
        for sku in sku_obj_list:
            sku.count = cart_dict[sku.id]['count']
            sku.selected = cart_dict[sku.id]['selected']

        # 序列化返回
        serializer = CartSKUSerializer(sku_obj_list, many=True)
        return Response(serializer.data)

    def put(self, request):
        """修改购物车"""
        # 校验
        s = self.get_serializer(data=request.data)
        s.is_valid(raise_exception=True)
        sku_id = s.validated_data["sku_id"]
        count = s.validated_data["count"]
        selected = s.validated_data["selected"]

        # 判断用户登录状态
        try:
            user = request.user
        except Exception as e:
            user = None

        # 保存
        if user and user.is_authenticated:
            # 用户登录,修改redis
            redis_conn = get_redis_connection("cart")
            pl = redis_conn.pipeline()

            # 处理数量
            pl.hset("cart_%s" % user.id, sku_id, count)
            # 处理勾选状态
            if selected:
                # 已勾选
                pl.sadd("cart_selected_%s" % user.id, sku_id)
            else:
                # 取消勾选
                pl.srem("cart_selected_%s" % user.id, sku_id)
            pl.execute()
            return Response(s.data)
        else:
            # 用户未登录, 修改cookie
            cookie_cart = request.COOKIES.get("cart")
            if cookie_cart:
                # 表示cookie中有购物车数据
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                # 表示cookie中没有购物车数据
                cart_dict = {}
            response = Response(s.data)

            if sku_id in cart_dict:
                cart_dict[sku_id] = {
                    "count": count,
                    "selected": selected
                }
                cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
                # 设置cookie
                response.set_cookie("cart", cart_cookie, max_age=constants.CART_COOKIE_EXPIRES)
            return response

    def delete(self, request):
        """删除购物车"""
        s = CartDeleteSerializer(data=request.data)
        s.is_valid(raise_exception=True)

        sku_id = s.validated_data["sku_id"]

        # 判断用户登录状态
        try:
            user = request.user
        except Exception as e:
            user = None

        # 删除
        if user and user.is_authenticated:
            # 从redis中删除
            redis_conn = get_redis_connection("cart")
            pl = redis_conn.pipeline()
            pl.srem("cart_selected_%s" % user.id, sku_id)
            pl.hdel("cart_%s" % user.id, sku_id)
            pl.execute()
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            # 从cookie中删除
            cookie_cart = request.COOKIES.get("cart")
            if cookie_cart:
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                # 表示cookie中没有购物车数据
                cart_dict = {}
            response = Response(status=status.HTTP_204_NO_CONTENT)
            if sku_id in cart_dict:
                del cart_dict[sku_id]
                cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
                # 设置cookie
                response.set_cookie("cart", cart_cookie,
                                    max_age=constants.CART_COOKIE_EXPIRES)
            return response


class CartSelectAllView(GenericAPIView):
    """购物车全选"""
    serializer_class = CartSelectAllSerializer

    def perform_authentication(self, request):
        pass

    def put(self, request):
        s = self.get_serializer(data=request.data)
        s.is_valid(raise_exception=True)

        selected = s.validated_data["selected"]

        # 判断登录状态
        try:
            user = request.user
        except Exception as e:
            user = None

        if user and user.is_authenticated:
            # 登录从redis
            redis_conn = get_redis_connection('cart')
            cart = redis_conn.hgetall('cart_%s' % user.id)
            # 取到所有的sku_id,列表
            sku_id_list = cart.keys()
            if selected:
                # 全选
                redis_conn.sadd('cart_selected_%s' % user.id, *sku_id_list)
            else:
                # 取消全选
                redis_conn.srem('cart_selected_%s' % user.id, *sku_id_list)
            return Response({'message': 'OK'})
        else:
            # cookie
            cookie_cart = request.COOKIES.get("cart")
            if cookie_cart:
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                # 表示cookie中没有购物车数据
                cart_dict = {}
            response = Response({'message': 'OK'})
            if cart_dict:
                for count_selected_dict in cart_dict.values():
                    count_selected_dict["selected"] = selected
                cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
                # 设置cookie
                response.set_cookie("cart", cart_cookie,
                                    max_age=constants.CART_COOKIE_EXPIRES)

            return response

